#include <iostream>
using namespace std;

// int main()
// {
    // 引用的特点 ------------------------------------
    // int a = 10;
    // // 必须初始化
    // //int &b; 
    // int &b = a; 

    // // 一个变量可以有多个引用
    // int &c = a;
    // printf("%p\n%p\n", &b, &c); // 地址相同，说明是同一个变量的别名
    // cout << endl;

    // // 引用一旦引用了一个实体，就不能在引用其他实体
    // int d = 20;
    // c = d; // 这里不是引用其他实体，而是对c赋值
    // printf("%p\n%p\n", &c, &d); // 可以看到c和d的地址不一样，说明不是一个变量

    // 常引用 -------------------------------

    // const常量只能用const引用类型进行引用
    // const int a = 10;
    // // int &b = a; // 编译器提示将 "int &" 类型的引用绑定到 "const int" 类型的初始值设定项时，限定符被丢弃C/C++(433)
    // const int &c = a;

    // // const引用也可以引用普通变量
    // int d = 20;
    // int &e = d;
    // const int &f = d;
    // printf("%p\n%p\n", &e, &f); // 通过观察地址可以发现ef都是d的引用

    // // 普通引用不可以给不同类型的变量取别名，但是const引用可以 -- 隐式类型转换
    // double g = 1.1;
    // //int &h = g; // 编译器提示无法用 "double" 类型的值初始化 "int &" 类型的引用(非常量限定)C/C++(434)
    // const int &i = g; // 隐式类型转换的过程中，实际上是将g拷贝给临时变量，再通过临时变量拷贝给i，临时变量是个常量，所以可以用const引用类型进行引用，这里实际是对临时变量取别名而不是对g，所以，i和g的地址也会有所不同
    // printf("%p\n%p\n", &g, &i);

//     return 0;
// }

// 使用场景 ------------------------------------

// 做参数
// // 这里的主要作用是为了防止拷贝，当参数为类类型的时候，传值参数会进行一次拷贝，这里会涉及到类的拷贝构造，如果是深拷贝，还可能涉及到动态内存的开辟，使用传引用可以避免拷贝，提高效率
// void swap(int &a, int &b)
// {
//     int tmp = a;
//     a = b;
//     b = tmp;
// }

// // 输出型参数，在C语言中我们使用指针将参数结果带回，但是指针的使用需要配合解引用操作符，稍有不胜就会发生错误
// // 引用类型做输出型参数可以按照普通常量的方式直接带回，更简洁
// void div(int &a, int &b, int &r)
// {
//     r = a % b;
// }

// int main()
// {
//     int a = 3;
//     int b = 2;
//     swap(a, b);
//     cout << a << " " << b << endl;

//     int c = 0;
//     div(a, b, c);
//     cout << c << endl;
//     return 0;
// }

// 做返回值 ----------------------------------
// // 传值返回时，会将返回的变量生成一份临时拷贝，如果太小会直接放到寄存器，太大会再创建函数栈帧的时候就提前开辟空间
// // 使用引用做返回值，可以减少临时拷贝，同时也会带来问题，因为普通变量在出了函数作用域之后会被销毁，会导致后续的操作会发生不可预料的事故
// // 推荐：出了函数作用域，如果返回对象还没有还给系统，则可以使用引用返回；如果还给系统了，只能使用传值返回
// int &add(int a, int b)
// {
//     static int c = a + b;
//     return c;
// }

// int main()
// {
//     int a = 1;
//     int b = 2;
//     int c = add(a, b);
//     cout << c << endl;
//     cout << c << endl;
// }

// inline内联函数----------------------------------------
// 在内联函数调用的地方直接将函数展开，不用开辟函数栈帧 -- 类似于C语言的宏

// 为什么不直接使用宏？
// 定义一个两个数求和的宏
// #define add(x, y) ((x)+(y))
// 可以看到宏的定义是比较复杂的，因为宏的作用是在函数中直接替换，所以容易写错且具有类型安全的问题

// 而内联函数直接就是函数的写法，对于开发者来说更容易把控，且debug模式下支持调试
inline int add(int a, int b)
{
    int c = a + b;
    return c;
}

int main()
{
    int a = 1;
    int b = 2;
    cout << add(a, b) << endl;

    return 0;
}
